﻿using Infrastructure.Extension;
using Medallion.Threading;
using Microsoft.EntityFrameworkCore;
using Quartz;

namespace Application.Job
{
    public class OperationQueueJob : IJob
    {
        private readonly ISchedulerFactory _schedulerFactory;
        private readonly JobManagerDbContext _dbContext;
        const int lock_d = 1;
        private readonly IDistributedLockProvider _synchronizationProvider;
        public OperationQueueJob(JobManagerDbContext dbContext, ISchedulerFactory schedulerFactory, IDistributedLockProvider synchronizationProvider)
        {
            _dbContext = dbContext;
            _schedulerFactory = schedulerFactory;
            _synchronizationProvider = synchronizationProvider;
        }
        // 操作：update、disable、delete
        public async Task Execute(IJobExecutionContext context)
        {
            using (this._synchronizationProvider.AcquireLock($"UserAccount2{Resource.OperationQueueJob}"))
            {
                var _scheduler = await _schedulerFactory.GetScheduler();
                var allOperation = await _dbContext.OperationQueue.ToListAsync();
                var hasServerDatas = allOperation.Where(s => s.ServerId == GlobalData.ServerId).OrderBy(s => s.CreateTime);
                var nonHasServerDatas = allOperation.Where(s => s.ServerId == 0).OrderBy(s => s.CreateTime);

                #region 操作：update、disable、delete
                if (hasServerDatas.Has())
                {
                    foreach (var item in hasServerDatas)
                    {
                        var jobData = await _dbContext.JobTask.FirstOrDefaultAsync(s => s.Id == item.JobId);
                        var dataId = item.JobId.ToString();
                        var jobKey = new JobKey(dataId, JobGroupName.Task);
                        switch (item.Type)
                        {
                            case OperationType.Update:
                                await _scheduler.RebuildJob(jobKey, jobData.Cron);
                                break;
                            case OperationType.Disable:
                                await _scheduler.DeleteJob(jobKey);
                                break;
                            case OperationType.Delete:
                                await _scheduler.DeleteJob(jobKey);
                                break;
                            default:
                                break;
                        }
                        _dbContext.Remove(item);
                    }
                    await _dbContext.SaveChangesAsync();
                }
                #endregion


                #region 丢失服务的操作：如操作后，服务停掉；刚启动且服务心跳检查未完成时操作；
                if (allOperation.Has())
                {
                    //10分钟内的数据重新分配新服务，超过1天的丢弃
                    var servers = await _dbContext.KeyValue.Select(s => s.Id).ToListAsync();
                    var lostServers = allOperation.Where(s => !servers.Contains(s.ServerId) && s.ServerId != 0);

                    var deletes = lostServers.Where(s => s.CreateTime < DateTime.Now.AddDays(-1));
                    _dbContext.RemoveRange(deletes);

                    var reAsigns = lostServers.Where(s => s.CreateTime > DateTime.Now.AddMinutes(-10)).ToList();
                    reAsigns.ForEach(s => s.ServerId = 0);

                    await _dbContext.SaveChangesAsync();
                }
                #endregion
            }
            return;
        }
    }

}
